#!/usr/bin/env python
'''
Created on 2011-5-18

@author: elm
'''


# -----------------------------------------------------------------------------
# calc.py
#
# A simple calculator with variables.   This is from O'Reilly's
# "Lex and Yacc", p. 63.
#
# Class-based example contributed to PLY by David McNab
# -----------------------------------------------------------------------------

import sys
sys.path.insert(0,"../..")

if sys.version_info[0] >= 3:
    raw_input = input

from ddbms.Parser import Parser

class SqlBaseParser(Parser):

    
    reserved = {
       'select' : 'SELECT',
       'from' : 'FROM',
       'where' : 'WHERE',
       'and' : 'AND',
       'or' : 'OR',
       'not' : 'NOT'   
    }
    
    tokens = [
        'NUMBER','STRING',    
        'NAME'
        ] + list(reserved.values())
    
    literals = ['=','<','>','(',')','.',',','*']
    
    def t_NAME(self,t):
        r'[a-zA-Z_][a-zA-Z0-9_]*'
        t.type = self.reserved.get(t.value,'NAME')
        return t;
    
    def t_NUMBER(self,t):
        r'\d+'
        #t.value = int(t.value)
        return t
    
    def t_STRING(self,t):
        r'[\'"].*?[\'"]'    
        return t;
    
    t_ignore = " \t"
    
    def t_newline(self,t):
        r'\n+'
        t.lexer.lineno += t.value.count("\n")
        
    def t_error(self,t):
        print("Illegal character '%s'" % t.value[0])
        t.lexer.skip(1)
        
        
    precedence = (   
        ('left','.') , 
        ('left',',') ,
        ('left','AND','OR'),
        ('right','NOT') ,      
        ('left','=') ,
        )
    
    def p_statement_nowhere(self,p):
        'statement : SELECT fieldrefs FROM tablerefs'
        p[0]=self.statement(p[2],p[4],None)
        
    #def statement_nowhere(self,fieldrefs,tablerefs):
    #    "OVERRIDED BY SUBCLASSES"
        
    def p_statement_where(self,p):
        'statement : SELECT fieldrefs FROM tablerefs WHERE expression'
        p[0]=self.statement(p[2],p[4],p[6])
    
    def p_fieldrefs_all(self,p):
        "fieldrefs : '*'"
        p[0] = self.fieldrefs_all()
        
    def p_fieldrefs_head(self,p):
        '''fieldrefs : colref fieldrefstail'''
        p[0] = self.fieldrefs([p[1]]+p[2])
        
    def p_fieldrefstail_tail(self,p):
        '''fieldrefstail : ',' colref fieldrefstail'''
        p[0]=[p[2]]+p[3]
    
    def p_fieldrefstail_empty(self,p):
        '''fieldrefstail : '''
        p[0]=[]
        
    def p_tablerefs_head(self,p):
        "tablerefs : tableref tablerefstail"
        p[0]=self.tablerefs([p[1]]+p[2])
    
    def p_tablerefstail_tail(self,p):
        "tablerefstail : ',' tableref tablerefstail"
        p[0]=[p[2]]+p[3]
    
    def p_tablerefstail_empty(self,p):
        "tablerefstail : "
        p[0]=[]
    
    def p_expression_binop(self,p):
        '''expression : expression AND expression
                      | expression OR expression'''
        op = self.ops(p[2])
        p[0] = self.condition_operation_binary(p[1],op,p[3])
        
    def p_expression_not(self,p):
        "expression : NOT expression"
        op = self.ops(p[1])
        p[0] = self.condition_operation_self(op,p[2])
    
    def p_expression_group(self,p):
        "expression : '(' expression ')'"
        p[0] = p[2]
    
    def p_expression_condition_simple_value(self,p):
        '''expression : colref '=' value
                      | colref '<' value
                      | colref '>' value'''
        op = self.ops(p[2])            
        p[0] = self.condition_value(p[1],op,p[3])
        
    def p_expression_condition_simple_field(self,p):
        '''expression : colref '=' colref
                      | colref '<' colref
                      | colref '>' colref''' 
        op = self.ops(p[2])            
        p[0] = self.condition_field(p[1],op,p[3])
    
    def p_expression_condition_multi_value(self,p):
        '''expression : colref '<' '=' value
                      | colref '>' '=' value
                      | colref '<' '>' value'''
        op = self.ops(p[2]+p[3])            
        p[0] = self.condition_value(p[1],op,p[4])
        
    def p_expression_condition_multi_field(self,p):
        '''expression : colref '<' '=' colref
                      | colref '>' '=' colref
                      | colref '<' '>' colref'''
        op = self.ops(p[2]+p[3])
        p[0] = self.condition_field(p[1],op,p[4])
    
    def p_tableref_simple(self,p):
        "tableref : NAME"
        p[0]=self.tableref(p[1])
    
    def p_colref_simple(self,p):
        '''colref : NAME'''  
        p[0]=self.fieldref(None,p[1])
    
    def p_colref_multi(self,p):
        '''colref : NAME '.' NAME'''
        p[0]=self.fieldref(self.tableref(p[1]),p[3])
    
    def p_value_number(self,p):
        '''value : NUMBER'''
        p[0] = self.value_number(p[1])
        
    def p_value_string(self,p):
        '''value : STRING'''
        str = self.value_string(p[1])
        if str.startswith('"') and str.endswith('"'):
            str = str[1:-1]
        if str.startswith("'") and str.endswith("'"):
            str = str[1:-1]
        p[0] = str
        
    def p_error(self,p):
        if p:
            print("Syntax error at '%s'" % p.value)
        else:
            print("Syntax error at EOF")

    